﻿# coding: utf-8
import wx
import weakref

from wxFramework.Dialog import wxDialogMaterialEdit
from Editor.History.CmdRemoveModel import CCmdRemoveModel

import SceneNode
import Entity
import EntityModel
import EntityTerrain

TREE_ITEM_SCENE_NODE = 1
TREE_ITEM_ENTITY = 2

class wxPanelHierarchy(wx.Panel):
    def __init__(self, parent, id):
        wx.Panel.__init__(self, parent, id)
        
        # create tree control.
        self._treeScene = wx.TreeCtrl(self, -1, style = wx.TR_HAS_BUTTONS|wx.TR_MULTIPLE)
        
        # layout
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self._treeScene, 1, wx.ALL|wx.EXPAND, border = 5)
        self.SetSizer(sizer)
        
        # make image list
        il = wx.ImageList(IL.IMAGE_SMALL, IL.IMAGE_SMALL)
        self._bmpIdxFolderNormal = il.Add(IL.GetBitmap(IL.ID_IMAGE_FILE_FOLDER_CLOSE, IL.IMAGE_SMALL))
        self._bmpIdxFolderExpand = il.Add(IL.GetBitmap(IL.ID_IMAGE_FILE_FOLDER_OPEN, IL.IMAGE_SMALL))
        self._bmpIdxFile = il.Add(IL.GetBitmap(IL.ID_IMAGE_FILE_NORMAL, IL.IMAGE_SMALL))
        self._bmpIdxFileSel = il.Add(IL.GetBitmap(IL.ID_IMAGE_FILE_SELECTED, IL.IMAGE_SMALL))
        self._bmpIdxType = il.Add(IL.GetBitmap(IL.ID_IMAGE_ASSETS_TYPE, IL.IMAGE_SMALL))
        self._bmpIdxRoot = il.Add(IL.GetBitmap(IL.ID_IMAGE_ASSETS, IL.IMAGE_SMALL))
        self._treeScene.SetImageList(il)
        self._il = il
        
        # add root item for scene.
        self._root = self._treeScene.AddRoot(TD.SCENE_ROOT_NODE, self._bmpIdxRoot)
        
        # define popup menu
        self.__DefinePopupMenu()
        
        # bind event.
        self._treeScene.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.__OnTreeItemActivated)
        self._treeScene.Bind(wx.EVT_TREE_KEY_DOWN, self.__OnTreeKeyDown)
        self._treeScene.Bind(wx.EVT_TREE_SEL_CHANGED, self.__OnTreeSelectChanged)
        
    def __DefinePopupMenu(self):
        """ Define a popup menu for terrain material edit """
        
        self._idEditTerrainMaterial = wx.NewId()
        
        self.Bind(wx.EVT_MENU, self.__OnMenuEditMaterial, id = self._idEditTerrainMaterial)
        
    def __OnMenuEditMaterial(self, e):
        """ Show material edit dialog to edit terrain material """
        
        materialHandle = TERRAIN_EDITOR.GetTerrainMaterialHandle()
        if not materialHandle:
            return
            
        dlg = wxDialogMaterialEdit(self)
        dlg.UpdateUI(materialHandle)
        dlg.ShowModal()
        dlg.Destroy()
        
    def __OnTreeSelectChanged(self, e):
        """ Process tree item selection changed """
        
        selections = self._treeScene.GetSelections()
        nodeRefList = []
        for sel in selections:
            data = self._treeScene.GetPyData(sel)
            if type(data) == tuple:
                treeItemType, data = data
                if treeItemType == TREE_ITEM_SCENE_NODE:
                    nodeRefList.append(data)
                    
        SCENE_EDITOR._selectedObjectRefList = nodeRefList
        e.Skip()
                
    def __OnTreeKeyDown(self, e):
        """ Process key down message on tree ctrl """
        
        selections = self._treeScene.GetSelections()
        if not selections:
            return
            
        keyCode = e.GetKeyCode()
        if keyCode == wx.WXK_DELETE:
            nodeList = []
            for sel in selections:
                data = self._treeScene.GetPyData(sel)
                if type(data) == tuple:
                    treeItemType, data = data
                    if treeItemType == TREE_ITEM_SCENE_NODE:
                        sceneNodeRef = data
                        node = sceneNodeRef()
                        if node:
                            nodeList.append(node)

            for node in nodeList:
                cmd = CCmdRemoveModel(modelNodeRef = weakref.ref(node))
                HISTORY_MANAGER.RunCommand(cmd)
        
    def __OnTreeItemActivated(self, e):
        """ Process double-click tree item """
        
        item = e.GetItem()
        data = self._treeScene.GetPyData(item)
        
        # entity.
        if type(data) == tuple:
            treeItemType, data = data
            if treeItemType == TREE_ITEM_SCENE_NODE:
                pass
            elif treeItemType == TREE_ITEM_ENTITY:
                sceneNodeRef, entityIdx = data
                sceneNode = sceneNodeRef()
                if sceneNode:
                    entityHandle = SceneNode.GetEntity(sceneNode.GetCoreHandle(), entityIdx)
                    entityType = Entity.GetType(entityHandle)
                    if entityType == Entity.ET_MODEL:
                        PANEL_PROPERTY.SetPanelProperty(PANEL_PROP_MATERIAL)
                        PANEL_PROP_MATERIAL.SetModelEntity(sceneNodeRef, entityIdx)
                    elif entityType == Entity.ET_TERRAIN:
                        menu = wx.Menu()
                        menu.Append(self._idEditTerrainMaterial, TD.EDIT_TERRAIN_MATERIAL)
                        self._treeScene.PopupMenu(menu)
                        menu.Destroy()                        
        
        e.Skip()
                                    
    def RefreshSelectedSceneNodeList(self):
        """ Refresh tree item selection state """
        
        self._treeScene.UnselectAll()
        for ref in SCENE_EDITOR._selectedObjectRefList:
            sceneNode = ref()
            if sceneNode:
                self._treeScene.SelectItem(sceneNode._treeItem)

    def OnRefreshSceneNode(self, sceneNode):
        """ Refresh a scene node in hierarchy panel. """
                
        self.__OnRefreshSceneNode(sceneNode)
        self._treeScene.Expand(self._root)
    
    def __OnRefreshSceneNode(self, sceneNode):
        """ Refresh a scene node in hierarchy panel """
                
        if not sceneNode._treeItem:
            return
            
        self._treeScene.DeleteChildren(sceneNode._treeItem)
        
        # Add all entities that are attached to this scene node.
        self.__AddSceneEntities(sceneNode._treeItem, sceneNode)
        
        # Add all child scene node.
        for node in sceneNode._children:
            self.__AddSceneNode(sceneNode._treeItem, node)
            self.__OnRefreshSceneNode(node)
            
    def __AddSceneNode(self, treeItem, sceneNode):
        """ Add a scene node tree item """
        
        item = self._treeScene.AppendItem(treeItem, sceneNode.GetName(), self._bmpIdxFile, self._bmpIdxFileSel)
        self._treeScene.SetPyData(item, (TREE_ITEM_SCENE_NODE, weakref.ref(sceneNode)))
        sceneNode._treeItem = item

    def __AddSceneEntities(self, treeItem, sceneNode):
        """ Add all entities that are attached to this scene node. """
        
        sceneNodeHandle = sceneNode.GetCoreHandle()
        entityCount = SceneNode.GetEntityCount(sceneNodeHandle)
        if entityCount > 0:
            itemEntityList = self._treeScene.AppendItem(treeItem, TD.ENTITY_LIST, self._bmpIdxFile)

            for i in xrange(0, entityCount):
                entityHandle = SceneNode.GetEntity(sceneNodeHandle, i)

                type = Entity.GetType(entityHandle)
                if type == Entity.ET_MODEL:
                    text = EntityModel.GetFileName(entityHandle)
                elif type == Entity.ET_TERRAIN:
                    text = EntityTerrain.GetFileName(entityHandle)
                    if not text:
                        text = u'Untitled'
                else:
                    return
                    
                item = self._treeScene.AppendItem(itemEntityList, text.decode('gbk'), self._bmpIdxFile)
                self._treeScene.SetPyData(item, (TREE_ITEM_ENTITY, (weakref.ref(sceneNode), i)))

        